from datetime import datetime, date, time
from typing import Optional, List, Dict, Any, Tuple
from apps.models.models import Student, User, User_Profiles, Coach, Appointments, Training_Programs
from apps.schemas.schemas import AppointmentCreateRequest, AppointmentUpdateRequest
from tortoise.transactions import in_transaction


async def get_all_appointments(page: int = 1, page_size: int = 10) -> Tuple[int, List[Dict[str, Any]]]:
    """
    获取所有预约列表（分页）
    :param page: 页码
    :param page_size: 每页数量
    :return: (总数, 预约列表)
    """
    # 计算偏移量
    offset = (page - 1) * page_size
    # 获取总数
    total = await Appointments.all().count()
    # 查询当前页的数据
    appointments = await Appointments.all().offset(offset).limit(page_size).values(
        "appointment_id",
        "student_id_id",
        "coach_id_id",
        "program_id_id",
        "appointment_date",
        "start_time",
        "end_time",
        "status"
    )

    # 处理外键字段名
    formatted_appointments = []
    for appointment in appointments:
        formatted_appointments.append({
            "appointment_id": appointment["appointment_id"],
            "student_id": appointment["student_id_id"],
            "coach_id": appointment["coach_id_id"],
            "program_id": appointment["program_id_id"],
            "appointment_date": appointment["appointment_date"],
            "start_time": appointment["start_time"],
            "end_time": appointment["end_time"],
            "status": appointment["status"]
        })

    return total, formatted_appointments


async def get_appointments_by_user_id(user_id: int) -> List[Dict[str, Any]]:
    """
    根据用户ID获取预约信息（学生或教练）
    :param user_id: 用户ID
    :return: 预约列表
    """
    try:
        # 尝试获取学生对象
        student = await Student.get_or_none(user_id=user_id)
        # 尝试获取教练对象
        coach = await Coach.get_or_none(user_id=user_id)

        # 如果既不是学生也不是教练
        if not student and not coach:
            raise ValueError("User is neither a student nor a coach")

        # 查询预约记录
        if student:
            # 学生查询自己的预约
            appointments = await Appointments.filter(student_id_id=student.student_id).all().prefetch_related(
                'coach_id__user_id', 'program_id', 'student_id__user_id'
            )
        else:
            # 教练查询与自己相关的预约
            appointments = await Appointments.filter(coach_id_id=coach.coach_id).all().prefetch_related(
                'student_id__user_id', 'program_id', 'coach_id__user_id'
            )

        if not appointments:
            return []

        appointment_list = []
        for appointment in appointments:
            try:
                # 获取教练用户信息
                coach_user = None
                if appointment.coach_id and hasattr(appointment.coach_id, 'user_id'):
                    # 正确获取教练关联的用户对象
                    coach_user = await User.get_or_none(user_id=appointment.coach_id.user_id_id)

                # 获取学生用户信息
                student_user = None
                if appointment.student_id and hasattr(appointment.student_id, 'user_id'):
                    # 正确获取学生关联的用户对象
                    student_user = await User.get_or_none(user_id=appointment.student_id.user_id_id)

                # 获取教练全名，如果不存在则使用用户名，否则为"Unknown"
                coach_fullname = "Unknown"
                if coach_user:
                    try:
                        user_profile = await User_Profiles.get_or_none(user_id=coach_user.user_id)
                        coach_fullname = user_profile.fullname if user_profile and user_profile.fullname else coach_user.username
                    except Exception:
                        coach_fullname = coach_user.username

                # 获取学生全名，如果不存在则使用用户名，否则为"Unknown"
                student_fullname = "Unknown"
                if student_user:
                    try:
                        user_profile = await User_Profiles.get_or_none(user_id=student_user.user_id)
                        student_fullname = user_profile.fullname if user_profile and user_profile.fullname else student_user.username
                    except Exception:
                        student_fullname = student_user.username

                # 格式化时间 - 处理 timedelta 对象
                def format_time(time_obj):
                    if time_obj is None:
                        return None
                    if hasattr(time_obj, 'isoformat'):
                        return time_obj.isoformat()
                    # 如果是 timedelta 对象，需要转换为字符串表示
                    if hasattr(time_obj, 'total_seconds'):
                        total_seconds = int(time_obj.total_seconds())
                        hours = total_seconds // 3600
                        minutes = (total_seconds % 3600) // 60
                        seconds = total_seconds % 60
                        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
                    return str(time_obj)

                appointment_list.append({
                    "appointment_id": appointment.appointment_id,
                    "student": {
                        "id": appointment.student_id_id if appointment.student_id_id else None,
                        "fullname": student_fullname
                    },
                    "coach": {
                        "id": appointment.coach_id_id if appointment.coach_id_id else None,
                        "fullname": coach_fullname
                    },
                    "program": {
                        "id": appointment.program_id_id if appointment.program_id_id else None,
                        "name": appointment.program_id.name if appointment.program_id else "Unknown"
                    },
                    "appointment_date": appointment.appointment_date.isoformat() if appointment.appointment_date else None,
                    "start_time": format_time(appointment.start_time),
                    "end_time": format_time(appointment.end_time),
                    "status": appointment.status
                })
            except Exception:
                # 如果处理单个预约时出错，继续处理其他预约
                continue

        return appointment_list
    except Exception as e:
        raise Exception(f"Error retrieving appointments: {str(e)}")


async def get_coach_appointments_by_status(
    user_id: int,
    page: int = 1,
    page_size: int = 10,
    status: Optional[str] = None
) -> Dict[str, Any]:
    """
    根据教练用户ID和状态筛选预约
    :param user_id: 教练用户ID
    :param page: 页码
    :param page_size: 每页数量
    :param status: 预约状态
    :return: 预约列表和分页信息
    """
    try:
        # 获取教练对象
        coach = await Coach.get_or_none(user_id=user_id)
        if not coach:
            raise ValueError("Coach not found")

        # 构建查询条件 - 始终查询该教练的预约
        query = Appointments.filter(coach_id_id=coach.coach_id)

        # 只有当status不是None且不为空字符串时才添加状态筛选条件
        if status is not None and status.strip() != "":
            query = query.filter(status=status)

        # 获取总数
        total = await query.count()

        # 应用分页
        offset = (page - 1) * page_size
        appointments = await query.offset(offset).limit(page_size).prefetch_related(
            'student_id__user_id', 'program_id', 'coach_id__user_id'
        )

        appointment_list = []
        for appointment in appointments:
            try:
                # 获取教练用户信息
                coach_user = None
                if appointment.coach_id and hasattr(appointment.coach_id, 'user_id'):
                    coach_user = await User.get_or_none(user_id=appointment.coach_id.user_id_id)

                # 获取学生用户信息
                student_user = None
                if appointment.student_id and hasattr(appointment.student_id, 'user_id'):
                    student_user = await User.get_or_none(user_id=appointment.student_id.user_id_id)

                # 获取教练全名
                coach_fullname = "Unknown"
                if coach_user:
                    try:
                        user_profile = await User_Profiles.get_or_none(user_id=coach_user.user_id)
                        coach_fullname = user_profile.fullname if user_profile and user_profile.fullname else coach_user.username
                    except Exception:
                        coach_fullname = coach_user.username

                # 获取学生全名
                student_fullname = "Unknown"
                if student_user:
                    try:
                        user_profile = await User_Profiles.get_or_none(user_id=student_user.user_id)
                        student_fullname = user_profile.fullname if user_profile and user_profile.fullname else student_user.username
                    except Exception:
                        student_fullname = student_user.username

                # 格式化时间
                def format_time(time_obj):
                    if time_obj is None:
                        return None
                    if hasattr(time_obj, 'isoformat'):
                        return time_obj.isoformat()
                    if hasattr(time_obj, 'total_seconds'):
                        total_seconds = int(time_obj.total_seconds())
                        hours = total_seconds // 3600
                        minutes = (total_seconds % 3600) // 60
                        seconds = total_seconds % 60
                        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
                    return str(time_obj)

                appointment_list.append({
                    "appointment_id": appointment.appointment_id,
                    "student": {
                        "id": appointment.student_id_id if appointment.student_id_id else None,
                        "fullname": student_fullname
                    },
                    "coach": {
                        "id": appointment.coach_id_id if appointment.coach_id_id else None,
                        "fullname": coach_fullname
                    },
                    "program": {
                        "id": getattr(appointment, 'program_id_id', None),
                        "name": appointment.program_id.name if appointment.program_id else "Unknown"
                    },
                    "appointment_date": appointment.appointment_date.isoformat() if appointment.appointment_date else None,
                    "start_time": format_time(appointment.start_time),
                    "end_time": format_time(appointment.end_time),
                    "status": appointment.status
                })
            except Exception:
                continue

        return {
            "list": appointment_list,
            "total": total,
            "page": page,
            "page_size": page_size
        }
    except Exception as e:
        raise Exception(f"Error retrieving coach appointments: {str(e)}")


async def get_appointment_by_id(appointment_id: int) -> Optional[Dict[str, Any]]:
    """
    根据预约ID获取预约信息
    :param appointment_id: 预约ID
    :return: 预约信息
    """
    appointment = await Appointments.get_or_none(appointment_id=appointment_id)
    if not appointment:
        return None

    return {
        "appointment_id": appointment.appointment_id,
        "student_id": appointment.student_id_id,
        "coach_id": appointment.coach_id_id,
        "program_id": appointment.program_id_id,
        "appointment_date": appointment.appointment_date,
        "start_time": appointment.start_time,
        "end_time": appointment.end_time,
        "status": appointment.status
    }


async def create_appointment(data: AppointmentCreateRequest) -> bool:
    """
    创建新的预约
    :param data: 预约创建请求数据
    :return: 创建是否成功
    """
    # 检查学生是否存在
    student = await Student.get_or_none(student_id=data.student_id)
    if not student:
        raise ValueError("Student not found")

    # 检查教练是否存在
    coach = await Coach.get_or_none(coach_id=data.coach_id)
    if not coach:
        raise ValueError("Coach not found")

    # 检查训练项目是否存在
    program = await Training_Programs.get_or_none(program_id=data.program_id)
    if not program:
        raise ValueError("Training program not found")

    try:
        async with in_transaction() as connection:
            # 创建预约
            await Appointments.create(
                student_id_id=student.student_id,
                coach_id_id=coach.coach_id,
                program_id_id=program.program_id,
                appointment_date=data.appointment_date,
                start_time=data.start_time,
                end_time=data.end_time,
                status=data.status,
                using_db=connection
            )
        return True
    except Exception as e:
        raise Exception(f"Error creating appointment: {str(e)}")


async def update_appointment(appointment_id: int, data: AppointmentUpdateRequest) -> bool:
    """
    更新预约信息
    :param appointment_id: 预约ID
    :param data: 预约更新请求数据
    :return: 更新是否成功
    """
    # 查询预约
    appointment = await Appointments.get_or_none(appointment_id=appointment_id)
    if not appointment:
        return False

    update_data = data.dict(exclude_unset=True)  # 只获取提供的字段

    # 更新预约表
    if any(k in update_data for k in ['appointment_date', 'start_time', 'end_time', 'status']):
        await appointment.update_from_dict({
            k: v for k, v in update_data.items()
            if k in ['appointment_date', 'start_time', 'end_time', 'status']
        })

    # 更新外键关系（如果提供了）
    if 'student_id' in update_data:
        student = await Student.get_or_none(student_id=update_data['student_id'])
        if not student:
            raise ValueError("Student not found")
        appointment.student_id_id = student.student_id

    if 'coach_id' in update_data:
        coach = await Coach.get_or_none(coach_id=update_data['coach_id'])
        if not coach:
            raise ValueError("Coach not found")
        appointment.coach_id_id = coach.coach_id

    if 'program_id' in update_data:
        program = await Training_Programs.get_or_none(program_id=update_data['program_id'])
        if not program:
            raise ValueError("Training program not found")
        appointment.program_id_id = program.program_id

    await appointment.save()
    return True


async def delete_appointment(appointment_id: int) -> bool:
    """
    删除预约
    :param appointment_id: 预约ID
    :return: 删除是否成功
    """
    appointment = await Appointments.get_or_none(appointment_id=appointment_id)
    if not appointment:
        return False

    await appointment.delete()
    return True


async def confirm_appointment(appointment_id: int) -> Optional[Dict[str, Any]]:
    """
    确认预约
    :param appointment_id: 预约ID
    :return: 更新后的预约信息
    """
    try:
        # 查询预约
        appointment = await Appointments.get_or_none(appointment_id=appointment_id)
        if not appointment:
            return None

        # 检查当前状态是否可以确认
        if appointment.status == "CANCELLED":
            raise ValueError("Cannot confirm a cancelled appointment")

        if appointment.status == "COMPLETED":
            raise ValueError("Cannot confirm a completed appointment")

        # 更新状态为已确认
        appointment.status = "CONFIRMED"
        await appointment.save()

        # 返回更新后的预约信息
        return {
            "appointment_id": appointment.appointment_id,
            "student_id": appointment.student_id_id,
            "coach_id": appointment.coach_id_id,
            "program_id": appointment.program_id_id,
            "appointment_date": appointment.appointment_date,
            "start_time": appointment.start_time,
            "end_time": appointment.end_time,
            "status": appointment.status
        }
    except Exception as e:
        raise Exception(f"Error confirming appointment: {str(e)}")


async def cancel_appointment(appointment_id: int) -> Optional[Dict[str, Any]]:
    """
    取消预约
    :param appointment_id: 预约ID
    :return: 更新后的预约信息
    """
    try:
        # 查询预约
        appointment = await Appointments.get_or_none(appointment_id=appointment_id)
        if not appointment:
            return None

        # 检查当前状态是否可以取消
        if appointment.status == "COMPLETED":
            raise ValueError("Cannot cancel a completed appointment")

        if appointment.status == "CANCELLED":
            raise ValueError("Appointment is already cancelled")

        # 更新状态为已取消
        appointment.status = "CANCELLED"
        await appointment.save()

        # 返回更新后的预约信息
        return {
            "appointment_id": appointment.appointment_id,
            "student_id": appointment.student_id_id,
            "coach_id": appointment.coach_id_id,
            "program_id": appointment.program_id_id,
            "appointment_date": appointment.appointment_date,
            "start_time": appointment.start_time,
            "end_time": appointment.end_time,
            "status": appointment.status
        }
    except Exception as e:
        raise Exception(f"Error cancelling appointment: {str(e)}")
